﻿/******************************************************
* author :  cwj
* email  :  chenwenji_360@live.com 
* history:  created by cwj 2017/4/14 22:43:09 
* clrversion :4.0.30319.42000
******************************************************/

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

namespace Machine.DataAccess.Common.ORM
{
    class AccessSchemInfo : DbSchemInfoBase
    {
        public AccessSchemInfo(ProviderElement providerElement) : base(providerElement) { }
        private static ConcurrentDictionary<string, string> primaryKeyCache = new ConcurrentDictionary<string, string>();
        //private static ConcurrentDictionary<string, bool> primaryKeyTypeCache = new ConcurrentDictionary<string, bool>();
        private static ConcurrentDictionary<string, DbForeignKeyInfo[]> fkCache = new ConcurrentDictionary<string, DbForeignKeyInfo[]>();
        protected override void RemoveFkCache(string type)
        {
            fkCache[type] = null;
        }

        public override string GetPrimaryKey(string tableName)
        {
            if (primaryKeyCache.ContainsKey(tableName)) return primaryKeyCache[tableName];
            using (var con = this.GetConnection())
            {
                var dataTable = con.GetSchema("Indexes");
                var primaryKey = from d in dataTable.AsEnumerable()
                                 where d.Field<string>("TABLE_NAME") == tableName && d.Field<bool>("PRIMARY_KEY")
                                 select new
                                 {
                                     TableName = d.Field<string>("TABLE_NAME").ToLower(),
                                     ColumnName = d.Field<string>("COLUMN_NAME").ToLower()
                                 };
                if (primaryKey.FirstOrDefault() != null) primaryKeyCache[tableName] = primaryKey.FirstOrDefault().ColumnName;
                if (primaryKeyCache.ContainsKey(tableName)) return primaryKeyCache[tableName];
                return null;
            }
        }

        public override bool GetPrimaryKeyType(string tableName)
        {
            return false;
        }

        public override DbForeignKeyInfo[] GetForeignKey(string tableName)
        {
            if (!fkCache.ContainsKey(tableName) || fkCache[tableName] == null)
            {
                using (var con = this.GetConnection())
                {
                    var schem = con.GetSchema("Indexes");
                    var result = from d in schem.AsEnumerable()
                                 where d.Field<string>("TABLE_NAME") == tableName && !d.Field<bool>("PRIMARY_KEY")
                                 select d.Field<string>("COLUMN_NAME");
                    List<DbForeignKeyInfo> list = new List<DbForeignKeyInfo>();
                    foreach (var item in result)
                    {
                        list.Add(new DbForeignKeyInfo()
                            {
                                From = item.ToLower(),
                                Table = item.Replace("Relation", "").ToLower(),
                                To = "id"
                            });
                    }
                    fkCache[tableName] = list.ToArray();
                }
            }
            return fkCache[tableName];
        }

        public override string[] GetAllTables()
        {
            var tableList = new List<string>();
            using (var con = this.GetConnection())
            {
                var schem = con.GetSchema("Tables");
                var result = from d in schem.AsEnumerable()
                             where d.Field<string>("TABLE_TYPE") == "TABLE"
                             select d.Field<string>("TABLE_NAME").ToLower();
                return result.ToArray();
            }
        }

        public override bool ExtistTable(string name)
        {
            using(var con = this.GetConnection())
            {
                var schem = con.GetSchema("Tables");
                return(from d in schem.AsEnumerable()
                              where d.Field<string>("TABLE_NAME") == name
                              select d).Count() > 0;
            }
        }

        public override Tuple<string, DbForeignKeyInfo[]> GetOuterFKey(Type bigTypeName, Type collectionTypeName)
        {
            throw new NotSupportedException("测试麻烦,Access数据库暂时不支持");
        }

        protected override ConcurrentSet<string> GetTableColums(string tableName)
        {
            using (var con = this.GetConnection())
            {
                var dataTable = con.GetSchema("Indexes");
                var primaryKey = from d in dataTable.AsEnumerable()
                                 where d.Field<string>("TABLE_NAME") == tableName && d.Field<bool>("PRIMARY_KEY")
                                 select new
                                 {
                                     TableName = d.Field<string>("TABLE_NAME").ToLower(),
                                     ColumnName = d.Field<string>("COLUMN_NAME").ToLower()
                                 };
                var columnsTable = con.GetSchema("Columns");
                var columns = from d in columnsTable.AsEnumerable()
                              where d.Field<string>("TABLE_NAME") == tableName
                              select new
                              {
                                  TableName = d.Field<string>("TABLE_NAME").ToLower(),
                                  ColumnName = d.Field<string>("COLUMN_NAME").ToLower()
                              };
                var result = columns.Except(primaryKey);
                var returnValue = new ConcurrentSet<string>();
                foreach (var item in result)
                {
                    returnValue.Add(item.ColumnName.ToLower());
                }
                return returnValue;
            }
        }
    }
}
